home *** CD-ROM | disk | FTP | other *** search
/ Windows Game Programming for Dummies (2nd Edition) / WinGamProgFD.iso / pc / DirectX SDK / DXSDK / samples / Multimedia / Demos / DMBoids / flock.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-10-31  |  8.3 KB  |  271 lines

  1. //-----------------------------------------------------------------------------
  2. // File: Flock.cpp
  3. //
  4. // Desc: 
  5. //       
  6. // Copyright (c) 1995-2001 Microsoft Corporation. All rights reserved.
  7. //-----------------------------------------------------------------------------
  8. #include <D3DX8.h>
  9. #include <stdio.h>
  10. #include "DXUtil.h"
  11. #include "boids.h"
  12. #include "music.h"
  13.  
  14. const float g_fInfluenceRadius = 10.0f;    // outside of this range forces are considered to be 0
  15.  
  16. const float CollisionFraction = 0.8f;
  17. const float InvCollisionFraction = 1.0f/(1.0f-CollisionFraction);
  18.  
  19. const float g_fNormalSpeed = 0.1f;
  20. const float    AngleTweak = 0.02f;
  21. const float g_fPitchToSpeedRatio = 0.002f;
  22.  
  23. // More arbitray constants that look cool
  24. const float    fSeparationScale    = 0.05f;
  25. const float    fAlignmentScale        = 0.1f;
  26. const float    fCohesionScale        = 1.0f;
  27. const float    fMigratoryScale        = 0.4f;
  28. const float    fObstacleScale        = 1.0f;
  29.  
  30.  
  31.  
  32.  
  33. //-----------------------------------------------------------------------------
  34. // Effects
  35. //-----------------------------------------------------------------------------
  36. extern BoidMusic g_Music;
  37. extern BOOL      g_bSeparation;
  38. extern BOOL      g_bAlignment;
  39. extern BOOL      g_bCohesion;
  40. extern BOOL      g_bMigratory;
  41. extern BOOL      g_bObstacle;
  42.  
  43.  
  44.  
  45.  
  46. //-----------------------------------------------------------------------------
  47. // Name: 
  48. // Desc: 
  49. //-----------------------------------------------------------------------------
  50. VOID CFlock::Update( FLOAT fElapsedTime )
  51. {
  52.     DWORD   i, j;
  53.     static DWORD lastobj = 0xffffffff;
  54.  
  55.     // First, update the dist array 0.0..1.0 with 0.0 being furthest away
  56.     for( i=0; i<m_dwNumBoids; i++ ) 
  57.     {
  58.         for( j=i+1; j<m_dwNumBoids; j++ ) 
  59.         {
  60.             D3DXVECTOR3 vDiff = m_Boids[i].vPos - m_Boids[j].vPos;
  61.             FLOAT       fDist = D3DXVec3Length( &vDiff );
  62.             m_afDist[i][j] = m_afDist[j][i] = fDist;
  63.         }
  64.         m_afDist[i][i] = 0.0f;
  65.  
  66.         // Reset boid forces
  67.         m_Boids[i].vSeparationForce = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  68.         m_Boids[i].vAlignmentForce  = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  69.         m_Boids[i].vCohesionForce   = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  70.         m_Boids[i].vMigratoryForce  = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  71.         m_Boids[i].vObstacleForce   = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  72.         m_Boids[i].dwNumNeighbors   = 0;
  73.     }
  74.  
  75.     // For each boid calculate the individual forces affecting it
  76.     for( i=0; i<m_dwNumBoids; i++ ) 
  77.     {
  78.         // Add in effects from other boids
  79.         for( j=i+1; j<m_dwNumBoids; j++ ) 
  80.         {
  81.             D3DXVECTOR3    vDiff = m_Boids[i].vPos - m_Boids[j].vPos;
  82.             FLOAT       fDist = D3DXVec3Length( &vDiff );
  83.  
  84.             // if i is near j have them influence each other
  85.             if( fDist < g_fInfluenceRadius ) 
  86.             {
  87.                 // Sum seperation force
  88.                 m_Boids[i].vSeparationForce += vDiff/(fDist*fDist);
  89.                 m_Boids[j].vSeparationForce -= vDiff/(fDist*fDist);
  90.  
  91.                 // sum alignment force (actually summing the directions of the neighbors)
  92.                 m_Boids[i].vAlignmentForce += m_Boids[j].vDir / fDist;
  93.                 m_Boids[j].vAlignmentForce += m_Boids[i].vDir / fDist;
  94.                 
  95.                 // sum cohesion force (actually we're summing neighbor locations)                
  96.                 m_Boids[i].vCohesionForce += m_Boids[j].vPos;
  97.                 m_Boids[j].vCohesionForce += m_Boids[i].vPos;
  98.  
  99.                 m_Boids[i].dwNumNeighbors++;
  100.                 m_Boids[j].dwNumNeighbors++;
  101.             }
  102.         }
  103.  
  104.         // Add in any obstacle forces
  105.         for( j=0; j<m_dwNumObstacles; j++ )
  106.         {
  107.             D3DXVECTOR3    vDiff     = m_Boids[i].vPos - m_Obstacles[j].vPos;
  108.             FLOAT       fObRadius = m_Obstacles[j].fRadius * 1.5f;
  109.  
  110.             // Ignore object if already past
  111.             if( D3DXVec3Dot( &vDiff, &m_Boids[i].vDir ) > 0.0f )
  112.                 continue;
  113.  
  114.             FLOAT fDist = D3DXVec3Length( &vDiff ) - fObRadius;
  115.  
  116.             if( fDist < g_fInfluenceRadius )
  117.             {
  118.                 if( ( lastobj != j ) && ( fDist < 5.0f ) )
  119.                 {
  120.                     lastobj = j;
  121.                     g_Music.Transition();
  122.                 }
  123.                 vDiff /= fDist;    // normalize
  124.  
  125.                 fDist -= fObRadius;
  126.                 if( fDist < 0.01f )
  127.                     fDist = 0.01f;
  128.                 
  129.                 m_Boids[i].vObstacleForce += vDiff;
  130.             }
  131.         }
  132.  
  133.         // Find cohesion force
  134.         if( m_Boids[i].dwNumNeighbors ) 
  135.         {
  136.             m_Boids[i].vCohesionForce /= (FLOAT)m_Boids[i].dwNumNeighbors;     // Find average location of neighbors
  137.             D3DXVECTOR3    vDiff = m_Boids[i].vCohesionForce - m_Boids[i].vPos; // Find delta to center of flock
  138.             FLOAT       fMag  = D3DXVec3Length( &vDiff );
  139.             
  140.             if( fMag > 0.0f)
  141.                 m_Boids[i].vCohesionForce = vDiff/fMag;    // normalized
  142.             else
  143.                 m_Boids[i].vCohesionForce = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
  144.         }
  145.  
  146.         // Find the alignment force
  147.         if( m_Boids[i].dwNumNeighbors != 0 ) 
  148.         {
  149.             m_Boids[i].vAlignmentForce /= (FLOAT)m_Boids[i].dwNumNeighbors;
  150.             FLOAT fMag = D3DXVec3Length( &m_Boids[i].vAlignmentForce );
  151.             
  152.             if( fMag > 0.0f ) 
  153.             {
  154.                 m_Boids[i].vAlignmentForce /= fMag;    // normalize
  155.                 
  156.                 D3DXVECTOR3    vDiff = m_Boids[i].vAlignmentForce - m_Boids[i].vDir;
  157.                 
  158.                 m_Boids[i].vAlignmentForce = vDiff / fMag;
  159.             } 
  160.         }
  161.  
  162.         // Finally, the migratory force
  163.         m_Boids[i].vMigratoryForce  = m_vGoal - m_Boids[i].vPos;
  164.         D3DXVec3Normalize( &m_Boids[i].vMigratoryForce, &m_Boids[i].vMigratoryForce );
  165.     }
  166.  
  167.     // Update the boids
  168.     for( i=0; i<m_dwNumBoids; i++ ) 
  169.     {
  170.         // Sum all the forces
  171.         D3DXVECTOR3    vForce( 0.0f, 0.0f, 0.0f );
  172.         if( !g_bObstacle )     vForce += m_Boids[i].vObstacleForce;
  173.         if( !g_bSeparation ) vForce += m_Boids[i].vSeparationForce;
  174.         if( !g_bAlignment )     vForce += m_Boids[i].vAlignmentForce * fAlignmentScale;
  175.         if( !g_bCohesion )     vForce += m_Boids[i].vCohesionForce;
  176.         if( !g_bMigratory )     vForce += m_Boids[i].vMigratoryForce;
  177.  
  178.         // Ok, now we have a final force to apply to the boid.
  179.         // Normalize it if too big.
  180.         FLOAT mag = D3DXVec3Length( &vForce );
  181.         if( mag > 1.0f )
  182.             vForce /= mag;
  183.  
  184.         // first deal with pitch changes
  185.         if( vForce.y > 0.01f ) 
  186.         {            // we're too low
  187.             m_Boids[i].pitch += AngleTweak;
  188.             if (m_Boids[i].pitch > 0.8f)
  189.                 m_Boids[i].pitch = 0.8f;
  190.         } 
  191.         else if( vForce.y < -0.01f ) 
  192.         {    // we're too high
  193.             m_Boids[i].pitch -= AngleTweak;
  194.             if (m_Boids[i].pitch < -0.8f)
  195.                 m_Boids[i].pitch = -0.8f;
  196.         }
  197.         else
  198.         {
  199.             // add damping
  200.             m_Boids[i].pitch *= 0.98f;
  201.         }
  202.  
  203.         // speed up or slow down depending on angle of attack
  204.         m_Boids[i].speed -= m_Boids[i].pitch * g_fPitchToSpeedRatio;
  205.         // damp back to normal
  206.         m_Boids[i].speed = (m_Boids[i].speed-g_fNormalSpeed)*0.99f + g_fNormalSpeed;
  207.  
  208.         // limit speed changes to +- 50% from normal
  209.         if( m_Boids[i].speed < g_fNormalSpeed/2 ) 
  210.             m_Boids[i].speed = g_fNormalSpeed/2;
  211.         if( m_Boids[i].speed > g_fNormalSpeed*5 ) 
  212.             m_Boids[i].speed = g_fNormalSpeed*5;
  213.  
  214.         // now figure out yaw changes
  215.         D3DXVECTOR3 vOffset = vForce;
  216.         vOffset.y = 0.0f;
  217.         D3DXVECTOR3 vDelta = m_Boids[i].vDir;
  218.  
  219.         if( D3DXVec3Length( &vOffset ) > 0.0f )
  220.             D3DXVec3Normalize( &vOffset, &vOffset );
  221.  
  222.         float    dot = D3DXVec3Dot( &vOffset, &vDelta );
  223.         // speed up slightly if not turning much
  224.         if (dot > 0.7f) 
  225.         {
  226.             dot -= 0.7f;
  227.             m_Boids[i].speed += dot * 0.005f;
  228.         }
  229.         D3DXVec3Cross( &vOffset, &vOffset, &vDelta );
  230. //        D3DXVec3Cross( &vOffset, &vDelta, &vOffset );
  231.         dot = (1.0f-dot)/2.0f * 0.07f;
  232.         if( vOffset.y > 0.05f ) 
  233.         {
  234.             m_Boids[i].dyaw = (m_Boids[i].dyaw*19.0f + dot) * 0.05f;
  235.         } 
  236.         else if( vOffset.y < -0.05f ) 
  237.         {
  238.             m_Boids[i].dyaw = (m_Boids[i].dyaw*19.0f - dot) * 0.05f;
  239.         } 
  240.         else
  241.         {
  242.             m_Boids[i].dyaw *= 0.98f;    // damp it
  243.         }
  244.         m_Boids[i].yaw += m_Boids[i].dyaw;
  245.         m_Boids[i].roll = -m_Boids[i].dyaw * 20.0f;
  246.  
  247.         // Take new info and create a new world matrix
  248.         // First translate into place, then set orientation, then scale (if needed)
  249.         D3DXMATRIX matTrans, matRotateX, matRotateY, matRotateZ, matTemp1, matTemp2;
  250.         D3DXMatrixTranslation( &matTrans, m_Boids[i].vPos.x, m_Boids[i].vPos.y, m_Boids[i].vPos.z );
  251.         D3DXMatrixRotationX( &matRotateX, -m_Boids[i].pitch );
  252.         D3DXMatrixRotationY( &matRotateY, -m_Boids[i].yaw );
  253.         D3DXMatrixRotationZ( &matRotateZ, -m_Boids[i].roll );
  254.         D3DXMatrixMultiply( &matTemp1, &matRotateX, &matRotateY );
  255.         D3DXMatrixMultiply( &matTemp2, &matRotateZ, &matTemp1 );
  256.         D3DXMatrixMultiply( &m_Boids[i].matWorld, &matTemp2, &matTrans );
  257.  
  258.         // Now extract the boid's direction out of the matrix
  259.         m_Boids[i].vDir.x = m_Boids[i].matWorld._31;
  260.         m_Boids[i].vDir.y = m_Boids[i].matWorld._32;
  261.         m_Boids[i].vDir.z = m_Boids[i].matWorld._33;
  262.  
  263.         // And update the boid's location
  264.         m_Boids[i].vPos += m_Boids[i].vDir * m_Boids[i].speed * 100 * fElapsedTime;
  265.     }
  266. }
  267.  
  268.  
  269.  
  270.  
  271.